﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

//

#pragma once
#include "GnufBase.h"
#include "GnufArrangementArea.h"
#include "GnufPallet.h"
#include "GnufInfo.h"
#include "GnufBaseUtils.h"
#include "GnufQtObjectPtr.h"

namespace gnuf {
    class Pallet;
    class QtBulletin;
    
    /*
        +---------------------------+
        |   ______   ______   ___   |
        |  |_ICON_| |_TEXT_| |_X_|  |
        +---------------------------+
    */
    struct GNUF_BASE_EXPORT BulletinDataToast
    {
        std::wstring icon;
        std::wstring text;
        bool wantCloseButton;
    };
    
    /*
        +---------------------------+
        |   _____________________   |
        |  |_TEXT_| ((()_ _30%___)  |
        +---------------------------+
    */
    struct GNUF_BASE_EXPORT BulletinDataProgressBar
    {
        Range<int> range;
        std::wstring text;
    };
    
    /*
        +-----------------------------------------------------------+
        |                   ____________________                    | .....
        |                  |____DOING___WHAT____|                   | 1st Section
        |                         _________                         | .....
        |                        /         \                        |
        |                       /           \                       |
        |                      (     30%     )                      | 2nd Section 
        |                       \           /                       |
        |                        \_________/                        |
        |                        ___________                        | .....
        |                       |__MESSAGE__|                       | 3rd Section
        |                    ___________________                    | .....
        |                   |______CAROUSEL_____|                   | 4th Section
        |               _____________________________               | .....
        |              |___________MINUTIAE__________|              | 5th Section
        |  ______                                 ________________  | .....
        | |_TIPS_|                               |_CANCEL/CONFIRM_| | 6th Section
        +-----------------------------------------------------------+ .....
    */
    typedef std::vector< std::pair<
        bool,                   // isText or isImage
        std::wstring            // Text or Image
    > > CarouselFrameSections;
    typedef std::vector< std::pair<
        bool,                   // isCaption or isImage
        CarouselFrameSections   // Text or Image
    > > CarouselFrames;
    struct GNUF_BASE_EXPORT BulletinDataProgressBoard
    {
        std::wstring doingWhat;
        Range<int> range;
        std::uint8_t format;
        std::wstring message;
        struct {
            bool doesSwitchFrameAutomatically()     const { return this->frameDisplayTime > 0; }
            bool doesSwitchFrameWhenValueChanged()  const { return this->frameDisplayTime < 1; }
            int frameDisplayTime; // milliseconds
            CarouselFrames frames;
        } carousel;
        std::vector< std::wstring > minutiae; // single or multi-line
        struct { std::wstring caption; std::wstring hyperlink; } help;
        bool cancelable;
        std::function<bool()> allowToCancel;
        bool waitForConfirmingAfterFinished;
        bool wantToStayOnTop;
    };

    /*
             Icon
            /
        +--/-----------------------+
        | □ Caption               ×|
        | Description              |
        |                          |
        |                  □  □  □ |
        +-------------------\------+
                             \ 
                              Button
    */
    struct GNUF_BASE_EXPORT BulletinDataNapkin
    {
        std::wstring icon;
        std::wstring caption;
        std::wstring description;
        std::vector<std::wstring> buttons;
    };

    class Bulletin;
    class GNUF_BASE_EXPORT IBulletinObserver : public gcmp::WeakReferenceable
    {
    public:
        virtual void onButtonClicked(const Bulletin *, int buttonIndex) = 0;
        virtual void onHeaderButtonClicked(const Bulletin*) = 0;
        virtual void onMouseEnter(const Bulletin *) {};
        virtual void onMouseLeave(const Bulletin *) {};
    };

    class GNUF_BASE_EXPORT Bulletin final 
        : public IArrangementAreaObserver
        , public IPalletEventHandler
    {
        CANNOT_COPY_OR_ASSIGN(Bulletin);
        typedef std::function<void()> WorkFunc;
        
    public:
        enum class EContentType : std::uint8_t {
            eToast,
            eProgressBar,
            eProgressBoard,
            eNapkin
        };
        
        // eToast.
        explicit Bulletin(
            const std::wstring & icon,
            const std::wstring & text,
            const bool wantCloseButton);
            
        // eProgressBar.
        explicit Bulletin(
            const int minimum,
            const int maximum,
            const int value,
            const std::wstring & text);
            
        // eProgressBoard.
        explicit Bulletin(
            // 1st Section
            const std::wstring & doingWhat,
            // 2nd Section
            const int minimum,
            const int maximum,
            const int value,
            const std::int8_t format, // 0:percentage, 1:value, 2:mode
            // 3rd Section
            const std::wstring & message,
            // 4th Section
            const int carouselFrameDisplayTime = 0, // milliseconds
            const CarouselFrames & carouselFrames = {},
            // 5th Section
            const std::vector< std::wstring > minutiae = {},
            // 6th Section
            const std::wstring & helpCaption = L"",
            const std::wstring & helpHyperlink = L"",
            const bool cancelable = false,
            const std::function<bool()> allowToCancel = nullptr,
            const bool waitForConfirmingAfterFinished = false,
            // Other Options
            const bool wantToStayOnTop = false);
            
        // eNapkin.
        explicit Bulletin(
            const std::wstring & caption,
            const std::wstring & description,
            const std::wstring & icon = L"",
            const std::vector< std::wstring > & buttons = {});
        ~Bulletin();

        ///\return Return true, if allow to start a progress.
        static bool allowToStartProgress();
        
        const Pallet * pallet() const;
              Pallet * pallet();

        ///\return Return the content type.
        EContentType contentType() const { return m_contentType; }

        ///\brief Play the fading-in animation not until show completely.
        void fadeIn(unsigned int millisecond, bool isModal = true);
        ///\brief Play the fading-out not until hide completely.
        void fadeOut(unsigned int millisecond);

        ///\brief Show completely.
        void show(bool isModal = true);
        ///\brief Hide completely.
        void hide();

        // Return true if the data is not nullptr. Otherwise, return false.
        bool hasDataToast()         const { return (nullptr != m_opDataToast.get()); }
        bool hasDataProgressBar()   const { return (nullptr != m_opDataProgressBar.get()); }
        bool hasDataProgressBoard() const { return (nullptr != m_opDataProgressBoard.get()); }
        bool hasDataProgress()      const { return (hasDataProgressBar() || hasDataProgressBoard()); }
        bool hasDataNapkin()        const { return (nullptr != m_opDataNapkin.get()); }
        // Return the data.
        const BulletinDataToast *           dataToast()         const { return m_opDataToast.get(); }
        const BulletinDataProgressBar *     dataProgressBar()   const { return m_opDataProgressBar.get(); }
        const BulletinDataProgressBoard *   dataProgressBoard() const { return m_opDataProgressBoard.get(); }
        const BulletinDataNapkin *          dataNapkin()        const { return m_opDataNapkin.get(); }
            
        ///\brief Set the value.
        ///\note The value must be in the range.
        void setValue(const int);
        ///\return Return the value.
        int value() const;

        ///\brief Set the text for the progress bar.
        void setProgressBarText(const std::wstring &text);

        ///\brief Set the doing what text for the progress board.
        void setDoingWhat(const std::wstring &);

        ///\return Return the minimum of the range.
        int minimum() const;
        ///\return Return the maximum of the range.
        int maximum() const;

        ///\brief Finish the progress.
        void finish();

        ///\brief Set the message.
        void setMessage(const std::wstring &);
        
        ///\brief Set the minutiae (single or multi-line).
        void setMinutiae(const std::vector< std::wstring > &);

        ///\return Return true if canceled. Otherwise, return false.
        bool isCanceled() const;

        ///\brief Set the work that will run in a child thread. 
        /// Meanwhile, the main thread is left for Qt rendering.
        void setWork(const std::function<void()> &work);

        ///\brief Set the key.
        void setKey(const std::string & val) { m_key = val; }
        ///\return Return the key.
        const std::string & key() const { return m_key; }

        ///\brief Set the observer to get callback.
        void setObserver(IBulletinObserver * pObserver) { m_wpObserver.Reset(pObserver); }
        ///\return Return the observer.
        const IBulletinObserver * observer() const { return (m_wpObserver.IsValid() ? m_wpObserver.Get() : nullptr); }
              IBulletinObserver * observer()       { return (m_wpObserver.IsValid() ? m_wpObserver.Get() : nullptr); }
        
    protected:
        // Inherited from IArrangementAreaObserver...
        virtual void onArrangementAreaEvent(ArrangementAreaEvent *) override;
        virtual void onLayoutRefreshed(const ArrangementArea * const) override;
        // Inherited from IPalletEventHandler...
        virtual bool onFooterButtonClicked(Pallet*) override;
        virtual void onHeaderButtonClicked(Pallet*) override;
        virtual void onRefreshStyle() override;
        virtual bool onKeyEvent(Pallet*, IPalletEventHandler::EKey) override;
        virtual void onMouseEvent(Pallet *, IPalletEventHandler::EMouse) override;
        virtual bool onIsMasked() const override;

    private:
        void show(const unsigned int *, bool);
        void hide(const unsigned int *);

        void beginToObserve(ArrangementArea *);
        void   endToObserve();

        void refreshPosition(const ArrangementArea * const, Pallet *) const;

        const Bulletin::EContentType m_contentType;
        enum class EMasked : std::uint8_t { eNo, eYes, eOverall };
        Bulletin::EMasked m_masked = Bulletin::EMasked::eNo; // unmasked
        gcmp::QtAutoPtr<QtBulletin> m_opQtBulletin;
        gcmp::OwnerPtr<BulletinDataToast> m_opDataToast;
        gcmp::OwnerPtr<BulletinDataProgressBar> m_opDataProgressBar;
        gcmp::OwnerPtr<BulletinDataProgressBoard> m_opDataProgressBoard;
        gcmp::OwnerPtr<BulletinDataNapkin> m_opDataNapkin;
        WorkFunc m_work;

        std::string m_key;
        gcmp::WeakPtr< IBulletinObserver > m_wpObserver;
    };
}
